package cool.mtc.base.plugin.generator.code.service.impl;

import cool.mtc.base.plugin.generator.code.CodeGeneratorProperties;
import cool.mtc.base.plugin.generator.code.exception.CodeGeneratorException;
import cool.mtc.base.plugin.generator.code.model.dto.DbColumnDTO;
import cool.mtc.base.plugin.generator.code.model.form.TemplateParamForm;
import cool.mtc.base.plugin.generator.code.model.query.DbColumnQuery;
import cool.mtc.base.plugin.generator.code.model.query.DbTableQuery;
import cool.mtc.base.plugin.generator.code.model.template.BaseTemplateParam;
import cool.mtc.base.plugin.generator.code.model.template.TemplateParamSupport;
import cool.mtc.base.plugin.generator.code.service.CodeGeneratorService;
import cool.mtc.core.util.FileUtil;
import cool.mtc.core.util.JdbcUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.Cleanup;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.*;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 明河
 */
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CodeGeneratorServiceImpl implements CodeGeneratorService {
    private final Configuration configuration;
    private final CodeGeneratorProperties codeGeneratorProperties;

    @Override
    public List<String> listTable(DbTableQuery query) {
        String sql = "SELECT `table_name` FROM information_schema.`TABLES` WHERE `table_schema` = ? ORDER BY `table_name`";
        Object[] params = {query.getDb()};
        try {
            return JdbcUtil.exec(query.getDbType(), query.getIp(), query.getPort(), query.getDb(), query.getUsername(), query.getPassword(), sql, params, String.class);
        } catch (SQLException | ClassNotFoundException ex) {
            throw new CodeGeneratorException(String.format("数据库语句执行出现错误，错误信息：%s", ex.getMessage()));
        }
    }

    @Override
    public List<DbColumnDTO> listColumn(DbColumnQuery query) {
        String sql = "SELECT " +
                "ORDINAL_POSITION AS orderIndex, " +
                "COLUMN_NAME AS columnName, " +
                "COLUMN_TYPE AS columnType, " +
                "DATA_TYPE AS dataType, " +
                "IF(IS_NULLABLE = 'YES', 1, 0) AS nullable, " +
                "COLUMN_COMMENT AS `comment` " +
                "FROM " +
                "information_schema.`COLUMNS` " +
                "WHERE " +
                "TABLE_SCHEMA = ? " +
                "AND TABLE_NAME = ?";
        Object[] params = {query.getDb(), query.getTable()};
        try {
            return JdbcUtil.exec(query.getDbType(), query.getIp(), query.getPort(), query.getDb(), query.getUsername(), query.getPassword(), sql, params, DbColumnDTO.class);
        } catch (SQLException | ClassNotFoundException ex) {
            throw new CodeGeneratorException(String.format("数据库语句执行出现错误，错误信息：%s", ex.getMessage()));
        }
    }

    @Override
    public void codeGenerate(TemplateParamForm form) {
        List<BaseTemplateParam> paramList;
        try {
            paramList = form.handleCheckParamCorrect();
        } catch (Exception ex) {
            throw new CodeGeneratorException(ex.getMessage());
        }
        paramList.forEach(this::generateCode);
    }

    /**
     * 生成代码
     */
    private <T extends TemplateParamSupport> void generateCode(T t) {
        // 模板
        Template template = this.getTemplate(t.getTemplateRelativePath());
        if (null == template) {
            return;
        }
        // 数据
        Map<String, Object> data = new HashMap<>();
        data.put("obj", t);
        // 输出
        this.generateFile(template, data, t.getTargetFilePath());
    }

    /**
     * 获取模板
     */
    private Template getTemplate(String templateRelativePath) {
        try {
            return configuration.getTemplate(templateRelativePath);
        } catch (IOException ex) {
            log.error("代码生成器 - 获取模板失败 - 模板路径：{} - 错误信息：{}", templateRelativePath, ex.getMessage());
            return null;
        }
    }

    /**
     * 生成文件
     */
    private void generateFile(Template template, Map<String, Object> data, String targetFilePath) {
        try {
            File generateFile = FileUtil.ensureFileExist(targetFilePath);
            @Cleanup Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(generateFile)));
            template.process(data, writer);
        } catch (TemplateException | IOException ex) {
            log.error("代码生成器 - 创建文件失败 - {} - 错误信息：{}", targetFilePath, ex.getMessage());
            return;
        }
        log.info("代码生成器 - 创建文件成功 - {}", targetFilePath);
    }
}
